﻿
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using RayDen.Library.Components.Color.Types;
using RayDen.Library.Core.Components;
using RayDen.Library.Core.Primitives;

namespace RayDen.RayEngine.Corrector.Managers
{

    public enum ColorMode
    {
        Rgb,
        PointSampledSpectrum,
        SingleWavelength,
    }

    public sealed class ColorManager : Singleton<ColorManager>
    {
        public ColorMode Mode;
        public bool Caching = false;
        private SampledSpectrum sampledSpectrum = new SampledSpectrum(1f);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public IColorType Unit()
        {
            if (Mode == ColorMode.PointSampledSpectrum)
                    return new PointSampledSpectrum(ref sampledSpectrum);
            return new RgbColor(1f);
        }

        private RgbColor zero;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public IColorType Zero()
        {

            if (Mode == ColorMode.PointSampledSpectrum)
                    return new PointSampledSpectrum();
            return new RgbColor();
        }

        public ColorManager()
        {
            if (GlobalConfiguration.Instance.SpectralRendering)
            {
                Mode = ColorMode.PointSampledSpectrum;
            }
            else
            {
                Mode = ColorMode.Rgb;
            }
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public IColorType Convert(ref RgbSpectrum col, SpectrumType type = SpectrumType.Reflectance)
        {
            switch (Mode)
            {
                case ColorMode.PointSampledSpectrum:
                    return new PointSampledSpectrum(ref col, type);
                case ColorMode.Rgb:
                    return new RgbColor(ref col);
            }
            return new RgbColor(ref col);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public IColorType Convert(RgbSpectrumInfo col, SpectrumType type = SpectrumType.Reflectance)
        {
            IColorType result;

            if (Caching)
            {
                if (Cache.ContainsKey(col.GetHashCode()))
                    return Cache[col.GetHashCode()];
            }
            switch (Mode)
            {
                case ColorMode.PointSampledSpectrum:
                    result= new PointSampledSpectrum(col, type);
                    break;
                case ColorMode.Rgb:
                    result= new RgbColor(col);
                    break;
                default:
                    result = new RgbColor(col);
                    break;
            }
            if (Caching)
            {
                if (!Cache.ContainsKey(col.GetHashCode()))
                {
                    Cache.TryAdd(col.GetHashCode(), result);
                }
            }

            return result;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public IColorType Convert(float[] col, SpectrumType type = SpectrumType.Reflectance)
        {
            switch (Mode)
            {
                case ColorMode.PointSampledSpectrum:
                    var rgb = new RgbSpectrum(col);
                    return new PointSampledSpectrum(ref rgb, type);
                case ColorMode.Rgb:
                    return new RgbColor(col);
            }

            return new RgbColor(col);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public IColorType Convert(SampledSpectrum col, SpectrumType type = SpectrumType.Reflectance)
        {
            switch (Mode)
            {
                case ColorMode.PointSampledSpectrum:
                    return new PointSampledSpectrum(ref col);
            }

            var rgbSpectrum = col.ToRgb();
            return new RgbColor(ref rgbSpectrum);
        }


        public ConcurrentDictionary<long, IColorType> Cache = new ConcurrentDictionary<long, IColorType>();


    }
}
